浏览器缓存
浏览器缓存机制有两种,一种为强缓存,一种为协商缓存。
- 强缓存 200 from cached, 内存,disk
- 直接从浏览器缓存中读取,不去后台查询是否过期
Expires过期时间,值是时间点。缺陷是必须保证服务端时间和客户端时间严格同步。Cache-Control:max-age=3600过期秒数(优先级更高)。解决了客户端和服务端时间必须同步的问题。
- 协商缓存 304 Not Modified
- 每次使用缓存之前先去后台确认一下
Last-ModifiedIf-Modified-Since上次修改时间。 值是二进制时间ETagIf-None-Match值是 hash 唯一标识串
对于强缓存,浏览器在第一次请求的时候,会直接下载资源,然后缓存在本地,第二次请求的时候,直接使用缓存。 对于协商缓存,第一次请求缓存且保存缓存标识与时间,重复请求向服务器发送缓存标识和最后缓存时间,服务端进行校验,如果失效则使用缓存。
为什么要有 ETag
HTTP1.1 中 ETag 的出现主要是为了解决几个 Last-Modified 比较难解决的问题:
- 某些服务器不能精确的得到文件的最后修改时间。
- 一些文件也许会周期性的更改,但是内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新 GET;
- 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说 1s 内修改了 N 次),
If-Modified-Since能检查到的粒度是秒级的,使用ETag就能够保证这种需求下客户端在 1 秒内能刷新 N 次 cache。
ETag 的生成方式
使用内容的散列,最后修改时间戳的哈希值,或简单地使用版本号。
Cache-Control
在 HTTP/1.1 中,Cache-Control 是最重要的规则,主要用于控制网页缓存,主要取值为:
- public:所有内容都将被缓存(客户端和代理服务器都可缓存)
- private:所有内容只有客户端可以缓存,Cache-Control 的默认取值
- no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
- no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- max-age=xxx (xxx is numeric):缓存内容将在 xxx 秒后失效
from memory cache and from disk cache
在浏览器中,浏览器会在 js 和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而 css 文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。
优先级
Cache-Control > expires > Etag / If-None-Match > Last-Modified / If-Modified-Since
讲讲 304 缓存的原理
- 服务器首先产生 ETag,服务器可在稍后使用它来判断页面是否已经被修改。本质上,客户端通过将该记号传回服务器要求服务器验证其(客户端)缓存
- 304 是 HTTP 状态码,服务器用来标识这个文件没修改,不返回内容,浏览器在接收到个状态码后,会使用浏览器已缓存的文件
- 客户端请求一个页面(A)。 服务器返回页面 A,并在给 A 加上一个 ETag。 客户端展现该页面,并将页面连同 ETag 一起缓存。 客户再次请求页面 A,并将上次请求时服务器返回的 ETag 一起传递给服务器。 服务器检查该 ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应 304(未修改——Not Modified)和一个空的响应体